package com.vhans.db.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.lang.Assert;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.vhans.core.domain.Card;
import com.vhans.core.domain.User;
import com.vhans.core.enums.FilePathEnum;
import com.vhans.core.redis.RedisService;
import com.vhans.core.strategy.context.UploadStrategyContext;
import com.vhans.core.utils.SecurityUtils;
import com.vhans.db.mapper.CardMapper;
import com.vhans.db.mapper.UserMapper;
import com.vhans.db.model.dto.ConditionDTO;
import com.vhans.db.model.dto.EmailDTO;
import com.vhans.db.model.dto.user.UserDTO;
import com.vhans.db.model.dto.user.UserInfoDTO;
import com.vhans.db.model.dto.user.UserPasswdDTO;
import com.vhans.db.model.vo.user.UserInfoVO;
import com.vhans.db.model.vo.user.UserVO;
import com.vhans.db.service.CardService;
import com.vhans.db.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.util.List;

import static com.vhans.core.constant.RedisConstant.CODE_KEY;

/**
 * 用户业务接口实现类
 *
 * @author vhans.db
 * @date 2022/12/05 15:32
 **/
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private RedisService redisService;

    @Autowired
    private UploadStrategyContext uploadStrategyContext;

    @Autowired
    private CardService cardService;

    @Override
    public List<UserVO> listUser(ConditionDTO condition) {
        return userMapper.listUserVO(condition);
    }


    @Override
    public void updateUser(UserDTO user) {
        // 更新用户信息
        User newUser = User.builder()
                .id(user.getId())
                .nickname(user.getNickname())
                .build();
        baseMapper.updateById(newUser);
    }

    @Override
    public UserInfoVO getInfo() {
        Integer userId = StpUtil.getLoginIdAsInt();
        User user = userMapper.selectOne(new LambdaQueryWrapper<User>()
                .select(User::getAvatar)
                .eq(User::getId, userId));
        List<Card> cards = cardService.selectCardListByUserId();
        return UserInfoVO.builder().id(userId).avatar(user.getAvatar()).cardList(cards).build();
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateUserEmail(EmailDTO email) {
        verifyCode(email.getEmail(), email.getCode());
        User newUser = User.builder()
                .id(StpUtil.getLoginIdAsInt())
                .email(email.getEmail())
                .build();
        userMapper.updateById(newUser);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public String updateUserAvatar(MultipartFile file) {
        // 头像上传
        String avatar = uploadStrategyContext.executeUploadStrategy(file, FilePathEnum.AVATAR.getPath());
        // 更新用户头像
        User newUser = User.builder()
                .id(StpUtil.getLoginIdAsInt())
                .avatar(avatar)
                .build();
        userMapper.updateById(newUser);
        return avatar;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateUserInfo(UserInfoDTO userInfo) {
        User newUser = User.builder()
                .id(StpUtil.getLoginIdAsInt())
                .nickname(userInfo.getNickname())
                .build();
        userMapper.updateById(newUser);
    }

    @Override
    public void updatePassword(UserPasswdDTO user) {
        verifyCode(user.getUsername(), user.getCode());
        User existUser = userMapper.selectOne(new LambdaQueryWrapper<User>()
                .select(User::getUsername)
                .eq(User::getUsername, user.getUsername()));
        Assert.notNull(existUser, "邮箱尚未注册！");
        // 根据用户名修改密码
        userMapper.update(new User(), new LambdaUpdateWrapper<User>()
                .set(User::getPassword, SecurityUtils.sha256Encrypt(user.getPassword()))
                .eq(User::getUsername, user.getUsername()));
    }

    /**
     * 校验验证码
     *
     * @param username 用户名
     * @param code     验证码
     */
    public void verifyCode(String username, String code) {
        String sysCode = redisService.getObject(CODE_KEY + username);
        Assert.notBlank(sysCode, "验证码未发送或已过期！");
        Assert.isTrue(sysCode.equals(code), "验证码错误，请重新输入！");
    }
}